package com.ranyk.www.api.admin;

import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import com.ranyk.www.base.BaseController;
import com.ranyk.www.constant.CommonReturnCode;
import com.ranyk.www.constant.UserReturnCode;
import com.ranyk.www.entity.AdminUserLoginLog;
import com.ranyk.www.enums.ResponseEnum;
import com.ranyk.www.pojo.vo.AdminLoginUserVO;
import com.ranyk.www.response.ResponseResult;
import com.ranyk.www.service.IAdminUserService;
import com.ranyk.www.util.ServletUtils;
import com.ranyk.www.util.SingletonLoginUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Date;
import java.util.Map;

/**
 * CLASS_NAME: AdminLoginController.java <br/>
 *
 * @author ranyk           <br/>
 * @version V1.0           <br/>
 * @description: 管理员登录表现层控制器  <br/>
 * @date: 2022-04-14 <br/>
 */
@Slf4j
@RestController
@Api(value = "管理员登录", tags = "管理员登录")
public class AdminLoginController extends BaseController {

    private Producer captchaProducer;

    private IAdminUserService adminUserService;

    @Autowired
    public void setCaptchaProducer(Producer captchaProducer) {
        this.captchaProducer = captchaProducer;
    }

    @Autowired
    public void setAdminUserService(IAdminUserService adminUserService) {
        this.adminUserService = adminUserService;
    }

    /**
     * 登录请求
     *
     * @param user {@link AdminLoginUserVO} 用户登录对象
     * @return 返回登录结果对象
     */
    @ResponseBody
    @PostMapping(value = "/login")
    @ApiOperation(value = "后端登录", notes = "根据登录名、加密登录密码、验证码登录账号", httpMethod = "POST")
    public ResponseResult login(@RequestBody AdminLoginUserVO user) {
        if (!SingletonLoginUtils.validate(user.getRegisterCode())) {
            log.error(UserReturnCode.REGISTER_CODE_ERROR.getMessage());
            return ResponseResult.builder().code(UserReturnCode.REGISTER_CODE_ERROR.getCode()).msg(UserReturnCode.REGISTER_CODE_ERROR.getMessage()).build();
        }

        Subject currentUser = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(user.getLoginName(), user.getLoginPassword());
        // 默认不记住密码
        token.setRememberMe(false);
        try {
            currentUser.login(token);
            AdminUserLoginLog userLoginLog = new AdminUserLoginLog(new Date(), ServletUtils.getIpAddress(), SingletonLoginUtils.getUserId(), ServletUtils.getUserOperatingSystem(), ServletUtils.getUserBrowser());
            Integer count = adminUserService.updateLogById(SingletonLoginUtils.getUserId(), userLoginLog);
            Map<String, Object> result = new HashedMap<>(3);
            result.put("token", count);
            result.put("loginName", user.getLoginName());
            return ResponseResult.builder().code(ResponseEnum.SUCCESS.getCode()).msg(ResponseEnum.SUCCESS.getMsg()).object(result).build();
        } catch (UnknownAccountException e) {
            log.error(UserReturnCode.USER_NOT_EXIST.getMessage(), e);
            return ResponseResult.builder().code(UserReturnCode.USER_NOT_EXIST.getCode()).msg(UserReturnCode.USER_NOT_EXIST.getMessage()).build();
        } catch (DisabledAccountException e) {
            log.error(UserReturnCode.USER_SUSPEND.getMessage(), e);
            return ResponseResult.builder().code(UserReturnCode.USER_SUSPEND.getCode()).msg(UserReturnCode.USER_SUSPEND.getMessage()).build();
        } catch (IncorrectCredentialsException e) {
            log.error(UserReturnCode.WRONG_PASSWORD.getMessage(), e);
            return ResponseResult.builder().code(UserReturnCode.WRONG_PASSWORD.getCode()).msg(UserReturnCode.WRONG_PASSWORD.getMessage()).build();
        } catch (ExcessiveAttemptsException e) {
            log.error(UserReturnCode.ACCOUNT_LOCK.getMessage(), e);
            return ResponseResult.builder().code(UserReturnCode.ACCOUNT_LOCK.getCode()).msg(UserReturnCode.ACCOUNT_LOCK.getMessage()).build();
        } catch (RuntimeException e) {
            log.error(CommonReturnCode.UNKNOWN_ERROR.getMessage(), e);
            return ResponseResult.builder().code(CommonReturnCode.UNKNOWN_ERROR.getCode()).msg(CommonReturnCode.UNKNOWN_ERROR.getMessage()).build();
        }
    }

    /**
     * GET 授权验证请求
     *
     * @return {@link ResponseResult} 对象
     */
    @ApiOperation(value = "管理员未授权", notes = "未授权跳转登录首页")
    @RequestMapping(value = "isAuthenticated", method = RequestMethod.GET)
    public ResponseResult isAuthenticated() {
        if (!SecurityUtils.getSubject().isAuthenticated()) {
            return ResponseResult.builder().code(ResponseEnum.FORBIDDEN.getCode()).msg(ResponseEnum.FORBIDDEN.getMsg()).build();
        }
        return ResponseResult.builder().code(ResponseEnum.SUCCESS.getCode()).msg(ResponseEnum.SUCCESS.getMsg()).build();
    }

    /**
     * 管理员退出登录
     *
     * @return {@link ResponseResult} 对象
     */
    @GetMapping(value = "/logout")
    @ApiOperation(value = "管理员退出", notes = "管理员退出")
    public ResponseResult logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return ResponseResult.builder().code(ResponseEnum.SUCCESS.getCode()).msg(ResponseEnum.SUCCESS.getMsg()).build();
    }

    /**
     * 获取验证码
     *
     * @param request  {@link HttpServletRequest} 对象
     * @param response {@link HttpServletResponse} 对象
     */
    @ApiOperation(value = "登录验证码", notes = "登录验证码")
    @GetMapping(value = "/captcha-image", produces = "image/jpeg")
    public ModelAndView getCaptchaImage(HttpServletRequest request, HttpServletResponse response) {
        // 禁止服务器端缓存
        response.setDateHeader("Expires", 0);
        // 设置标准的 HTTP/1.1 no-cache headers.
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        // 设置IE扩展 HTTP/1.1 no-cache headers (use addHeader).
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        // 设置标准 HTTP/1.0 不缓存图片
        response.setHeader("Pragma", "no-cache");
        // 返回一个 jpeg 图片，默认是text/html(输出文档的MIMI类型)
        response.setContentType("image/jpeg");
        // 为图片创建文本
        String capText = captchaProducer.createText();
        // 将文本保存在session中，这里就使用包中的静态变量吧
        request.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);
        // 创建带有文本的图片
        BufferedImage bi = captchaProducer.createImage(capText);
        // 图片数据输出
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            ImageIO.write(bi, "jpg", out);
            out.flush();
        } catch (Exception e) {
            log.error("获取验证码时发生异常,异常对象为: ", e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    log.error("关闭输出流时发生异常,异常对象为: ", e);
                }
            }
        }
        return null;
    }

}
